
package privatemessanger;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.util.ArrayList;

/**
 * This is the main frame.
 * The frame is listening to all events.
 * @author  Erez Fatal, Oren Slor, Elad Yanai, Sigal Agami, Chen Ben Shabat,
 *          Inbar Pardo, Islamm Heralla, Ziv Hadary, Oren Shalev, Ortal David.
 */
public class MainFrame extends JFrame implements ActionListener , ListSelectionListener
{
    final public static int PORT=3333;
    public static boolean _isServer=false;
    public static boolean _isMute=false;
    private JMenuBar _menuBar; // the frame's menu bar.
    private JMenu _file,_connection,_help; // the menu bar's options.
    private JMenuItem _logIn,_register,_type,_password,_statistics,_exit,_server,_client,_myIP,_about; // the menu's item.
    private JCheckBoxMenuItem _sendAll; // the send to all check box.
    private JCheckBoxMenuItem _mute; // the mute check box.
    public static JTextField _popUp; // the pop-up for incoming message.
    private static Log _log; // the log instance.
    public static TextPanel _text; // the Text panel.
    public static ServerNamePanel _serverName; // the serverName panel.
    public static ContactNamePanel _contactName; // the contactName panel.
    public static MessagePanel _message; // the Message panel.
    public static Client _user=null; // the user who runs this application.
    public static ArrayList<ConnectToHost> _connectionArray; // array of connection.
    public static Statistics _statisticsInfo=null;
    private String _str;
    private Color _color;

    /**
     * This is the MainFrame constructor.
     * It initializes all panels.
     */
    MainFrame()
    {
        setTitle("MESSENGER");
        setSize(1000,700);
        setResizable(false);
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension screenSize = tk.getScreenSize();
        int screenHeight = screenSize.height;
        int screenWidth = screenSize.width;
        setLocation(screenWidth / 8, screenHeight / 8);

        _menuBar= new JMenuBar();
        _file=new JMenu("File");
        _menuBar.add(_file);
        _connection=new JMenu("Connection");
        _menuBar.add(_connection);
        _help=new JMenu("Help");
        _menuBar.add(_help);
        _logIn=new JMenuItem("Log in");
        _logIn.addActionListener(this);
        _logIn.setEnabled(false); // we don't support a database so there is no use for log in yet.
        _file.add(_logIn);
        _register=new JMenuItem("Register");
        _register.addActionListener(this);
        _file.add(_register);
        _type=new JMenuItem("Change Type");
        _type.addActionListener(this);
        _type.setEnabled(false);
        _file.add(_type);
        _password=new JMenuItem("Change Password");
        _password.addActionListener(this);
        _password.setEnabled(false);
        _file.add(_password);
        _statistics=new JMenuItem("Statistics");
        _statistics.addActionListener(this);
        _statistics.setEnabled(false);
        _file.add(_statistics);
        _mute=new JCheckBoxMenuItem("Mute Sound");
        _mute.addActionListener(this);
        _file.add(_mute);
        _exit=new JMenuItem("Exit");
        _exit.addActionListener(this);
        _file.add(_exit);
        _server=new JMenuItem("Create a new Server");
        _server.addActionListener(this);
        _server.setEnabled(false);
        _connection.add(_server);
        _client=new JMenuItem("Connect to an exist Server");
        _client.addActionListener(this);
        _client.setEnabled(false);
        _connection.add(_client);
        _myIP=new JMenuItem("My IP");
        _myIP.addActionListener(this);
        _help.add(_myIP);
        _about=new JMenuItem("About");
        _about.addActionListener(this);
        _help.add(_about);
        setJMenuBar(_menuBar);
        _connectionArray=new ArrayList<ConnectToHost>();
        _log=new Log();

        addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                if (_isServer)
                    _user.getServerArray().get(0).closeServer();
                else if (_user!=null && _connectionArray!=null)
                {
                    for (int i=0; i<_connectionArray.size(); i++)
                        _connectionArray.get(i).writeSocket("BYE "+_user.getID()+" "+_user.getUserName());
                }
                if(_statisticsInfo!=null)
                    _statisticsInfo.write();
                System.exit(0);
            }
        });

        Container contentPane=getContentPane();
        SpringLayout layout=new SpringLayout();
        contentPane.setLayout(layout);

        _serverName=new ServerNamePanel(this);
        contentPane.add(_serverName);
        _contactName=new ContactNamePanel(this);
        contentPane.add(_contactName);
        _message=new MessagePanel(this);
        contentPane.add(_message);
        _text=new TextPanel(this);
        contentPane.add(_text);
        JLabel servers=new JLabel("Servers:");
        contentPane.add(servers);
        JLabel contacts=new JLabel("Contacts:");
        contentPane.add(contacts);
        JLabel messages=new JLabel("Messages:");
        contentPane.add(messages);
        _sendAll=new JCheckBoxMenuItem("Send To All ?");
        _sendAll.setState(false);
        _sendAll.addActionListener(this);
        contentPane.add(_sendAll);
        _popUp=new JTextField();
        _popUp.setEditable(false);
        _popUp.setBackground(Color.yellow);
        _popUp.setText("                                                                                                                                              ");
        _popUp.setVisible(false);
        contentPane.add(_popUp);


        layout.putConstraint(SpringLayout.WEST, _serverName,0, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, _serverName,20, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, _contactName,200, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, _contactName,20, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, _message,400, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, _message,20, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.NORTH, _text,560, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, _text,400, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.WEST, servers,5, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, servers,5, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, contacts,205, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, contacts,5, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, messages,405, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, messages,5, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.NORTH, _sendAll,620, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, _sendAll,860, SpringLayout.WEST, contentPane);
        layout.putConstraint(SpringLayout.NORTH, _popUp,620, SpringLayout.NORTH, contentPane);
        layout.putConstraint(SpringLayout.WEST, _popUp,405, SpringLayout.WEST, contentPane);
    }

    /**
     * Get the current user.
     * @return The current client who use the application in this session.
     */
    public Client getUser() { return _user; }

    /**
     * Set the current client who use the application in this session.
     * @param User A client.
     */
    public void setUser(Client user) { _user=user; }

    /**
     * Get the log instance.
     * @return The instance of the history log.
     */
    public static Log getLog() { return _log; }

    /**
     * Get the Contact Name panel.
     * @return The instance of the Contact Name panel.
     */
    public ContactNamePanel getContactName() { return _contactName; }

    /**
     * This method changes the options which the user can do after a successful log in.
     */
    public void LogInSucceed()
    {
        _logIn.setEnabled(false);
        _register.setEnabled(false);
        _password.setEnabled(true);
        _server.setEnabled(true);
        _client.setEnabled(true);
    }

    /**
     * This method changes the options which the user can do after a successful registration.
     */
    public void regSucceed()
    {
        _logIn.setEnabled(false);
        _register.setEnabled(false);
        _password.setEnabled(false); // we don't support a database so there is no use for change password yet.
        _server.setEnabled(true);
        _client.setEnabled(true);
    }

    /**
     * This method changes the options which the user can do after a successful server creation.
     */
    public void hostSucceed()
    {
        _server.setEnabled(false); // we don't support a connection between servers yet.
        _client.setEnabled(false);
        _statistics.setEnabled(true);
        _statisticsInfo = new Statistics();
        _serverName.updateList();
    }

    /**
     * This method changes the options which the user can do after a successful connection to server.
     */
    public void toHostSucceed()
    {
        _type.setEnabled(true);
        _server.setEnabled(false);
        _serverName.updateList();
    }

    /**
     * This method inform all servers about the new type of the user.
     */
    public void changeTypeSucceed()
    {
        if (!_user.getType().equalsIgnoreCase(_str))
        {
            for (int i=0; i<_connectionArray.size(); i++)
            {
                _contactName.getListModel().insertElementAt(_user.getServerArray().get(i).getClientArray().get(i).getUserName()+" ("+_user.getServerArray().get(i).getClientArray().get(i).getType()+")", 0);
                _contactName.getListModel().remove(1);
                _connectionArray.get(i).writeSocket("NEW_TYPE "+_user.getType());
            }
        }
    }

    /**
     * This method has to handle events.
     * @param e Event which cause by the user in the GUI.
     */
    public void actionPerformed(ActionEvent e)
    {
        Object source = e.getSource();
        if (source==_exit)
        {
            if (_isServer)
                    _user.getServerArray().get(0).closeServer();
            else if (_user!=null && _connectionArray!=null)
            {
                for (int i=0; i<_connectionArray.size(); i++)
                    _connectionArray.get(i).writeSocket("BYE "+_user.getID()+" "+_user.getUserName());
            }
            if(_statisticsInfo!=null)
                    _statisticsInfo.write();
            System.exit(0);
        }
        if (source==_logIn)
        {
            // TODO new window - log in with: ID and password.
        }
        if (source==_register)
        {
            this.setVisible(false);
            new RegWindow(this);
        }
        if (source==_type)
        {
            _str=_user.getType();
            this.setVisible(false);
            new TypeWindow(this);
        }
        if (source==_password)
        {
            // TODO new window - the user is requested to enter an old password and a new password.
        }
        if (source==_statistics)
        {
           new StatisticsWindow(this);
        }

        if (source==_mute)
        {
            _isMute=_mute.getState();
        }

        if (source==_server)
        {
            this.setVisible(false);
            new HostWindow(this);
        }
        if (source==_client)
        {
            this.setVisible(false);
            new LoginWindow(this);
        }
        if (source==_myIP)
        {
            try {
                String IP=java.net.InetAddress.getLocalHost().getHostAddress();
                JOptionPane.showMessageDialog(this, "Your IP address is: "+IP,"My IP",JOptionPane.INFORMATION_MESSAGE);
            } catch(Exception error){error.printStackTrace();}
        }
        if (source==_about)
        {
            new AboutWindow(this);
        }

        if (source==_sendAll)
        {
            if (_sendAll.getState()==true)
            {
                _message.cleanText();
                _contactName.cleanSelectedClient();
                _contactName.getList().setSelectedIndex(-1);
                _contactName.getList().setEnabled(false);
                _color=_sendAll.getBackground();
                _sendAll.setBackground(Color.orange);
                int serverIndex=_serverName.getList().getSelectedIndex();
                if (serverIndex!=-1)
                    _text.getSendButton().setEnabled(true);
            }
            else
            {
                _contactName.getList().setEnabled(true);
                _sendAll.setBackground(_color);
                _text.getSendButton().setEnabled(false);
                _message.cleanText();
                _contactName.cleanSelectedClient();
                _text.getSendButton().setEnabled(false);
                int contactIndex=_contactName.getList().getSelectedIndex();
                int serverIndex=_serverName.getList().getSelectedIndex();
                if (contactIndex!=-1 && serverIndex!=-1)
                {
                    if (_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex).getID()!=_user.getID())
                    {
                        _contactName.setSelectedClient(_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex));
                        _text.getSendButton().setEnabled(true);
                        for (int i=0; i<_user.getMessageArray().size(); i++)
                        {
                            if (_user.getMessageArray().get(i).getSenderID()==_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex).getID() || _user.getMessageArray().get(i).getReceiverID()==_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex).getID())
                                _message.addText(_user.getMessageArray().get(i));
                        }
                    }
                }
            }
        }

        if (source==_text.getSendButton() && !_text.isEmpty() && _user!=null && _sendAll.getState())
        {
            if (_isServer)
            {
                for (int i=0; i<_user.getServerArray().get(0).getConnectionArray().size(); i++)
                {
                    _contactName.setSelectedClient(_user.getServerArray().get(0).getConnectionArray().get(i).getClient());
                    Message message=_text.getMessage();
                    if (message.getSenderID()==message.getReceiverID())
                        continue;
                    _log.sendMsg(message);
                    _log.closeLog();
                    for (int j=0; j<_user.getServerArray().get(0).getConnectionArray().size(); j++)
                    {
                        if (_user.getServerArray().get(0).getConnectionArray().get(j).getClient().getID()==message.getReceiverID() && _user.getServerArray().get(0).getConnectionArray().get(j).getClient().getUserName().equals(message.getReceiverName()))
                        {
                            _user.getMessageArray().add(message);
                            _user.getServerArray().get(0).getConnectionArray().get(j).writeSocket(message.getProtocol()+" "+message.getMessage());
                        }
                    }
                }
                _text.clearText();
                _contactName.cleanSelectedClient();
            }
            else
            {
                int serverIndex=_serverName.getList().getSelectedIndex();
                if (serverIndex!=-1)
                {
                    for (int i=0; i<_user.getServerArray().get(serverIndex).getClientArray().size(); i++)
                    {
                        _contactName.setSelectedClient(_user.getServerArray().get(serverIndex).getClientArray().get(i));
                        Message message=_text.getMessage();
                        if (message.getSenderID()==message.getReceiverID())
                            continue;
                        _user.getMessageArray().add(message);
                        _connectionArray.get(serverIndex).writeSocket(message.getProtocol()+" "+message.getMessage());
                    }
                    _text.clearText();
                    _contactName.cleanSelectedClient();
                }
            }
        }

        if(source==_text.getSendButton() && !_text.isEmpty() && _user!=null && _contactName.getSelectedClient()!=null)
        {
            Message message=_text.getMessage();
            if (message.getSenderID()==message.getReceiverID())
                return;
            _message.addText(message);
            _log.sendMsg(message);
            _log.closeLog();
            if (_isServer)
            {
                for (int i=0; i<_user.getServerArray().get(0).getConnectionArray().size(); i++)
                {
                    if (_user.getServerArray().get(0).getConnectionArray().get(i).getClient().getID()==message.getReceiverID() && _user.getServerArray().get(0).getConnectionArray().get(i).getClient().getUserName().equals(message.getReceiverName()))
                    {
                        _user.getMessageArray().add(message);
                        _user.getServerArray().get(0).getConnectionArray().get(i).writeSocket(message.getProtocol()+" "+message.getMessage());
                    }
                }
            }
            else
            {
                int serverIndex=_serverName.getList().getSelectedIndex();
                _user.getMessageArray().add(message);
                _connectionArray.get(serverIndex).writeSocket(message.getProtocol()+" "+message.getMessage());
            }
            _text.clearText();
        }
        if (source==_text.getCleanButton())
        {
            _message.cleanText();
            if (_contactName.getSelectedClient()!=null)
            {
                for (int i=0; i<_user.getMessageArray().size(); i++)
                {
                    if (_user.getMessageArray().get(i).getReceiverID()==_contactName.getSelectedClient().getID() || _user.getMessageArray().get(i).getSenderID()==_contactName.getSelectedClient().getID())
                    {
                        _user.getMessageArray().remove(i);
                        i--;
                    }
                }
            }
        }
    }

    /**
     * This method has to handle events.
     * @param e Event which cause by the user in the GUI.
     */
    public void valueChanged(ListSelectionEvent e)
    {
        Object source = e.getSource();
        _popUp.setVisible(false);
        if (source==_serverName.getList())
        {
            _contactName.getListModel().clear();
            _contactName.cleanSelectedClient();
            int serverIndex=_serverName.getList().getSelectedIndex();
            if (serverIndex!=-1)
            {
                if (_sendAll.getState())
                    _text.getSendButton().setEnabled(true);
                for(int i =0;i<_user.getServerArray().get(serverIndex).getClientArray().size();i++)
                    _contactName.getListModel().addElement(_user.getServerArray().get(serverIndex).getClientArray().get(i).getUserName()+" ("+_user.getServerArray().get(serverIndex).getClientArray().get(i).getType()+")");
            }
        }
        if (source==_contactName.getList())
        {
            _message.cleanText();
            _contactName.cleanSelectedClient();
            if (!_sendAll.getState())
                _text.getSendButton().setEnabled(false);
            int contactIndex=_contactName.getList().getSelectedIndex();
            int serverIndex=_serverName.getList().getSelectedIndex();
            if (contactIndex!=-1 && serverIndex!=-1)
            {
                if (_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex).getID()!=_user.getID())
                {
                    _contactName.setSelectedClient(_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex));
                    _text.getSendButton().setEnabled(true);
                    for (int i=0; i<_user.getMessageArray().size(); i++)
                    {
                        if (_user.getMessageArray().get(i).getSenderID()==_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex).getID() || _user.getMessageArray().get(i).getReceiverID()==_user.getServerArray().get(serverIndex).getClientArray().get(contactIndex).getID())
                            _message.addText(_user.getMessageArray().get(i));
                    }
                }
            }
        }
    }

    /**
     * This method has to handle the csae which the user press the enter key in the text box.
     * @param source
     */
    public void action(Object source)
    {
        if (!_text.isEmpty() && _user!=null && _sendAll.getState())
        {
            if (_isServer)
            {
                for (int i=0; i<_user.getServerArray().get(0).getConnectionArray().size(); i++)
                {
                    _contactName.setSelectedClient(_user.getServerArray().get(0).getConnectionArray().get(i).getClient());
                    Message message=_text.getMessage();
                    if (message.getSenderID()==message.getReceiverID())
                        continue;
                    _log.sendMsg(message);
                    _log.closeLog();
                    for (int j=0; j<_user.getServerArray().get(0).getConnectionArray().size(); j++)
                    {
                        if (_user.getServerArray().get(0).getConnectionArray().get(j).getClient().getID()==message.getReceiverID() && _user.getServerArray().get(0).getConnectionArray().get(j).getClient().getUserName().equals(message.getReceiverName()))
                        {
                            _user.getMessageArray().add(message);
                            _user.getServerArray().get(0).getConnectionArray().get(j).writeSocket(message.getProtocol()+" "+message.getMessage());
                        }
                    }
                }
                _text.clearText();
                _contactName.cleanSelectedClient();
            }
            else
            {
                int serverIndex=_serverName.getList().getSelectedIndex();
                if (serverIndex!=-1)
                {
                    for (int i=0; i<_user.getServerArray().get(serverIndex).getClientArray().size(); i++)
                    {
                        _contactName.setSelectedClient(_user.getServerArray().get(serverIndex).getClientArray().get(i));
                        Message message=_text.getMessage();
                        if (message.getSenderID()==message.getReceiverID())
                            continue;
                        _user.getMessageArray().add(message);
                        _connectionArray.get(serverIndex).writeSocket(message.getProtocol()+" "+message.getMessage());
                    }
                    _text.clearText();
                    _contactName.cleanSelectedClient();
                }
            }
        }

        if(!_text.isEmpty() && _user!=null && _contactName.getSelectedClient()!=null)
        {
            Message message=_text.getMessage();
            if (message.getSenderID()==message.getReceiverID())
                return;
            _message.addText(message);
            _log.sendMsg(message);
            _log.closeLog();
            if (_isServer)
            {
                for (int i=0; i<_user.getServerArray().get(0).getConnectionArray().size(); i++)
                {
                    if (_user.getServerArray().get(0).getConnectionArray().get(i).getClient().getID()==message.getReceiverID() && _user.getServerArray().get(0).getConnectionArray().get(i).getClient().getUserName().equals(message.getReceiverName()))
                    {
                        _user.getMessageArray().add(message);
                        _user.getServerArray().get(0).getConnectionArray().get(i).writeSocket(message.getProtocol()+" "+message.getMessage());
                    }
                }
            }
            else
            {
                int serverIndex=_serverName.getList().getSelectedIndex();
                _user.getMessageArray().add(message);
                _connectionArray.get(serverIndex).writeSocket(message.getProtocol()+" "+message.getMessage());
            }
            _text.clearText();
        }
    }
}
